﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace Microsoft.Tools.CodeRunner.Tasks
{
    public class Csr : Task
    {
        private string scriptPath;
        private string arguments;
        private bool? debugMessages;
        private bool? stackTraces;
        private bool? searchSystemPath;
        private bool? allowUnsafeCode;
        private int exitCode = 0;

        [Required] 
        public string ScriptPath 
        { 
            get { return scriptPath; } 
            set { scriptPath = value; } 
        }
        
        public string Arguments 
        { 
            get { return arguments; }
            set { arguments = value; }
        }
        
        public bool DebugMessages 
        { 
            get { return debugMessages ?? false; }
            set { debugMessages = value; } 
        }
        
        public bool StackTraces
        { 
            get { return stackTraces ?? false; }
            set { stackTraces = value; } 
        }
        
        public bool SearchSystemPath
        { 
            get { return searchSystemPath ?? false; }
            set { searchSystemPath = value; } 
        }
        
        public bool AllowUnsafeCode
        {
            get { return allowUnsafeCode ?? false; }
            set { allowUnsafeCode = value; } 
        }

        /// <summary>
        /// Specifies location where the task loads the underlying executable file (csr.exe).  If not specified
        /// then the task looks for the executable next to the task assembly and then in '$(ProgramFiles)\Code Runner .NET'
        /// </summary>
        public string ToolPath { get; set; }

        [Output] 
        public int ExitCode { get; set; }

        public override bool Execute()
        {
            string csrExe = "csr.exe";
            
            // First we need to find a csr.exe to run
            if (!String.IsNullOrEmpty(ToolPath))
            {
                if (Directory.Exists(ToolPath))
                {
                    csrExe = Path.Combine(ToolPath, csrExe);
                }
                else
                {
                    Log.LogWarning("Supplied ToolPath directory '{0}' does not exist and has been ignored", ToolPath);
                }
            }
            else
            {
                // Look next to the task assembly for the executable
                string dir = Assembly.GetExecutingAssembly().Location;
                string path = Path.Combine(dir, csrExe);
                
                if (!File.Exists(path))
                {
                    // Use the well know installation location
                    bool is64BitProcess = Marshal.SizeOf(typeof(IntPtr)) == 8;
                    string programFilesDir = is64BitProcess ? 
                        Environment.GetEnvironmentVariable("ProgramFiles(x86)") : 
                        Environment.GetEnvironmentVariable("ProgramFiles");
                    
                    if (programFilesDir != null)
                    {
                        dir = Path.Combine(programFilesDir, "Code Runner .NET");
                    }
                    else
                    {
                        Log.LogError("Could not not locate ProgramFiles directory");
                        return false;
                    }

                    path = Path.Combine(dir, csrExe);
                    
                    if (!File.Exists(path))
                    {
                        Log.LogError("Could not locate csr.exe executable in ToolPath, next to task assembly or at '{0}'", path);
                        return false;
                    }
                }

                csrExe = path;
            }
            
            ProcessStartInfo si = new ProcessStartInfo(csrExe);
            
            ConfigBuilder configBuilder = new ConfigBuilder();

            configBuilder.AppendIfNotNull("DebugMessages", debugMessages);
            configBuilder.AppendIfNotNull("StackTraces", stackTraces);
            configBuilder.AppendIfNotNull("SearchSystemPath", searchSystemPath);
            configBuilder.AppendIfNotNull("AllowUnsafeCode", allowUnsafeCode);
            
            if (configBuilder.Count > 0)
                si.EnvironmentVariables["CSR_CONFIG"] = configBuilder.ToString();
            
            si.Arguments = scriptPath + " " + arguments;

            Process process = null;
            bool ok = false;
            
            try 
            {
                process = Process.Start(si);
                
                if (process != null)
                {
                    process.WaitForExit();
                    ok = true;
                    exitCode = process.ExitCode;
                }
                else
                {
                    Log.LogErrorWithCodeFromResources("UnableToLaunch");
                }
            }
            finally
            {
                if (process != null)
                {
                    process.Close();
                    process = null;
                }
            }
            
            return ok;
        }
    }
}
